#include "shmem.h"
#include "msg_queue_peer.h"
#include "cJSON.h"
#include "modbus_my.h"

// 定义全局互斥锁
pthread_mutex_t modbus_mutex = PTHREAD_MUTEX_INITIALIZER;

void JSON_parse();
void *getdata(void *arg);
void *write_coil(void *arg);

int main(int argc, char const *argv[])
{
    // 解析数据点表
    JSON_parse();
    // 创建modbus实例 初始化 Modbus TCP 客户端
    modbus_t *md = modbus_new_tcp(mb_slave_ip, mb_slave_port);
    if (md == NULL)
    {
        perror("new tcp error");
        return -1;
    }
    // 设置modbus的从机id
    if (modbus_set_slave(md, 1) < 0)
    {
        perror("set slave error");
        return -1;
    }
    // 建立连接
    if (modbus_connect(md) < 0)
    {
        perror("connect error");
        return -1;
    }

    pthread_t tid_read, tid_write;
    if (pthread_create(&tid_read, NULL, getdata, (void *)md))
    {
        perror("create read_registers error");
        return -1;
    }
    if (pthread_create(&tid_write, NULL, write_coil, (void *)md))
    {
        perror("create wriye_coil error");
        return -1;
    }

    pthread_join(tid_read, NULL);
    pthread_join(tid_write, NULL);
    printf("线程结束\n");

    // 销毁互斥锁
    pthread_mutex_destroy(&modbus_mutex);

    modbus_close(md);
    modbus_free(md);
    // 释放内存
    shm_del(&para);
    // 释放节点数组内存
    free(node_arr);
    node_arr = NULL;

    return 0;
}

// JSON_parse函数保持不变...
void JSON_parse()
{
    char buf[1024] = {}; // 存放json文件中的字符串内容
    // 打开json文件
    FILE *fp = fopen("node.json", "r");
    if (fp == NULL)
    {
        perror("fopen error");
        return;
    }
    // 读取文件内容
    size_t size = fread(buf, sizeof(char), sizeof(buf), fp);
    if (size == 0)
    {
        perror("fread error");
        fclose(fp);
        return;
    }
    // 解析JSON 反序列化json
    cJSON *root = cJSON_Parse(buf);
    if (root == NULL)
    {
        perror("cJSON_Parse error");
    }
    // 获取mb_dev节点
    cJSON *mb_dev = cJSON_GetObjectItem(root, "mb_dev");
    // 获取mb_dev节点中的addr ip地址
    cJSON *mb_ip = cJSON_GetObjectItem(mb_dev, "addr");
    strcpy(mb_slave_ip, mb_ip->valuestring);
    // 获取mb_dev节点中的port端口
    cJSON *mb_port = cJSON_GetObjectItem(mb_dev, "port");
    mb_slave_port = mb_port->valueint;
    cJSON *modbus = cJSON_GetObjectItem(root, "modbus");
    cJSON *data = cJSON_GetObjectItem(modbus, "data");
    int data_size = cJSON_GetArraySize(data);
    mb_arr = (std_node *)malloc(data_size * STD_NODE_SIZE);
    if (mb_arr == NULL)
    {
        perror("mb_arr malloc error");
        return;
    }
    for (int i = 0; i < data_size; i++)
    {
        cJSON *item = cJSON_GetArrayItem(data, i);
        cJSON *key = cJSON_GetObjectItem(item, "key"); // 获取编号
        mb_arr[i].key = key->valueint;
        cJSON *type = cJSON_GetObjectItem(item, "type"); // 获取寄存器类型
        mb_arr[i].type = type->valueint;
    }
    cJSON_Delete(root); // 关闭

}

void *getdata(void *arg)
{
    int ret = -1;
    ret = shm_init(&para, "shm_test", 1024);
    if (ret < 0)
    {
        perror("shm_init error");
        return NULL;
    }
    // 获取共享内存地址
    void *node_p = shm_getaddr(&para);
    if (node_p == NULL)
    {
        perror("shm_getaddr error");
        return NULL;
    }
    // total指向共享内存中数据节点总个数
    total = (int *)node_p;
    // node_arr指向共享内存中节点缓存数组头
    node_arr = (std_node *)(node_p + sizeof(int));

    while (1)
    {
        modbus_t *md = (modbus_t *)arg;

        // 加锁保护modbus操作
        pthread_mutex_lock(&modbus_mutex);

        // 读保持寄存器
        int rec_t = modbus_read_registers(md, 0, 4, inputs);
        if (rec_t < 0)
        {
            perror("读取保持寄存器失败");
            pthread_mutex_unlock(&modbus_mutex);
            exit(0);
        }

        int coil_t = modbus_read_bits(md, 0, 2, coils); // 读多个线圈
        if (coil_t < 0)
        {
            perror("读取线圈状态失败");
            pthread_mutex_unlock(&modbus_mutex);
            exit(0);
        }

        // 解锁
        pthread_mutex_unlock(&modbus_mutex);

        // 更新共享内存数据
        *total = 10;
        int j = 0;
        int k = 0;

        // 遍历保持寄存器的内容
        for (int i = 0; i < 4; i++)
        {
            j = i + 4;
            node_arr[j].key = mb_arr[i].key;
            node_arr[j].type = mb_arr[i].type;
            node_arr[j].old_val.f_val = node_arr[j].new_val.f_val;
            node_arr[j].new_val.f_val = inputs[i];
            node_arr[j].ret = 0;
            node_arr[j].dev_type = 2;
        }

        // 遍历线圈的内容
        for (int i = 0; i < 2; i++)
        {
            j = i + 8;
            k = i + 4;
            node_arr[j].key = mb_arr[k].key;
            node_arr[j].type = mb_arr[k].type;
            node_arr[j].old_val.f_val = node_arr[j].new_val.f_val;
            node_arr[j].new_val.f_val = coils[i];
            node_arr[j].ret = 0;
            node_arr[j].dev_type = 2;
        }

        // sleep(1);
    }
}

void *write_coil(void *arg)
{
    modbus_t *md = (modbus_t *)arg;
    msgqueue msgval;
    while (1)
    {
        int ret = msg_queue_recv("topic", &msgval, sizeof(msgval), 2, 0);
        printf("%ld   %d   %s\n", msgval.mtype, msgval.key, msgval.mdata);
        if (ret < 0)
        {
            perror("消息队列接收失败");
            exit(0);
        }

        // 加锁保护modbus操作
        pthread_mutex_lock(&modbus_mutex);

        if (strcmp(msgval.mdata, "valve=0") == 0)
        {
            int coil_t = modbus_write_bit(md, 0, 0); // 写单个线圈
            if (coil_t < 0)
            {
                perror("写入线圈状态失败(valve=0)");
                pthread_mutex_unlock(&modbus_mutex);
                exit(0);
            }
            else
            {
                printf("valve=0\n");
            }
        }
        else if (strcmp(msgval.mdata, "valve=1") == 0)
        {
            int coil_t = modbus_write_bit(md, 0, 1); // 写单个线圈
            if (coil_t < 0)
            {
                perror("写入线圈状态失败(valve=1)");
                pthread_mutex_unlock(&modbus_mutex);
                exit(0);
            }
            else
            {
                printf("valve=1\n");
            }
        }
        else if (strcmp(msgval.mdata, "detergent=0") == 0)
        {
            int coil_t = modbus_write_bit(md, 1, 0); // 写单个线圈
            if (coil_t < 0)
            {
                perror("写入线圈状态失败(detergent=0)");
                pthread_mutex_unlock(&modbus_mutex);
                exit(0);
            }
            else
            {
                printf("detergent=0\n");
            }
        }
        else if (strcmp(msgval.mdata, "detergent=1") == 0)
        {
            int coil_t = modbus_write_bit(md, 1, 1); // 写单个线圈
            if (coil_t < 0)
            {
                perror("写入线圈状态失败(detergent=1)");
                pthread_mutex_unlock(&modbus_mutex);
                exit(0);
            }
            else
            {
                printf("detergent=1\n");
            }
        }

        // 解锁
        pthread_mutex_unlock(&modbus_mutex);
    }
    pthread_exit(NULL);
}
